<template>
  <div ref="list" :style="{ height }" class="chat-list-container" @scroll="scrollEvent">
    <div ref="phantom" class="chat-list-phantom"></div>
    <div ref="content" class="chat-list">
      <div class="chat-list-item" :ref="(el) => setItemRef(el, item._index)" :id="item._index" :key="item._index" v-for="item in visibleData">
        <component
          :is="getItemComponent(item.item)"
          v-bind="getItemProps(item.item)"
          @play-tts="handlePlayTTS"
          @stop-tts="handleStopTTS"
          @update-audio-url="handleUpdateAudioUrl"
        />
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, computed, onMounted, onUpdated, watch, nextTick } from 'vue'
import AiMessage from '../MessageItem/AiMessage.vue'
import UserMessage from '../MessageItem/UserMessage.vue'
import ttsService from '@/services/TTSService.js'
import MarkdownService from '@/services/MarkdownService.js'
const props = defineProps({
  // 聊天消息数据
  messages: {
    type: Array,
    default: () => []
  },
  // 估计的每个消息的高度
  estimatedItemSize: {
    type: Number,
    default: 80
  },
  // 缓冲区比例
  bufferScale: {
    type: Number,
    default: 2
  },
  // 列表高度
  height: {
    type: String,
    default: '100%'
  },
  // TTS是否启用
  ttsEnabled: {
    type: Boolean,
    default: true
  }
})

// const emit = defineEmits(['message-updated'])

const list = ref(null)
const phantom = ref(null)
const content = ref(null)
const items = ref([])

// 设置item引用
const setItemRef = (el, index) => {
  if (el) {
    const indexNum = +index.slice(1) // 移除下划线前缀
    items.value[indexNum] = el
  }
}

const screenHeight = ref(0)
const start = ref(0)
const end = ref(0)
const playingMessageId = ref(null)
// 动态组件解析
const getItemComponent = (message) => {
  return message && message.role === 'user' ? UserMessage : AiMessage
}

// 计算传入子组件的属性，避免无效 prop 透传
const getItemProps = (message) => {
  const base = {
    message,
    isPlaying: playingMessageId.value === message.id,
    ttsEnabled: props.ttsEnabled
  }
  if (message && message.role === 'assistant') {
    return { ...base, showVoiceSelector: true }
  }
  return base
}

const positions = ref([])

// 虚拟列表数据
const _listData = computed(() => {
  return props.messages.map((message, index) => ({
    _index: `_${index}`,
    item: message
  }))
})

// 可见的item数量
const visibleCount = computed(() => {
  return Math.ceil(screenHeight.value / props.estimatedItemSize)
})

// 上方缓冲区数量
const aboveCount = computed(() => {
  return Math.min(start.value, props.bufferScale * visibleCount.value)
})

// 下方缓冲区数量
const belowCount = computed(() => {
  return Math.min(props.messages.length - end.value, props.bufferScale * visibleCount.value)
})

// 可见的item数据
const visibleData = computed(() => {
  let startIdx = start.value - aboveCount.value
  let endIdx = end.value + belowCount.value
  return _listData.value.slice(startIdx, endIdx)
})

// 初始化位置
const initPositions = () => {
  positions.value = props.messages.map((message, index) => ({
    index,
    height: props.estimatedItemSize,
    top: index * props.estimatedItemSize,
    bottom: (index + 1) * props.estimatedItemSize
  }))
}

// 获取开始索引
const getStartIndex = (scrollTop = 0) => {
  return binarySearch(positions.value, scrollTop)
}

// 二分查找
const binarySearch = (list, value) => {
  let start = 0
  let end = list.length - 1
  let tempIndex = null

  while (start <= end) {
    let midIndex = Math.floor((start + end) / 2)
    let midValue = list[midIndex].bottom
    if (midValue === value) {
      return midIndex + 1
    } else if (midValue < value) {
      start = midIndex + 1
    } else if (midValue > value) {
      if (tempIndex === null || tempIndex > midIndex) {
        tempIndex = midIndex
      }
      end = midIndex - 1
    }
  }
  return tempIndex
}

// 更新item大小
const updateItemsSize = () => {
  let nodes = items.value.filter(node => node) // 过滤掉undefined的节点
  nodes.forEach((node) => {
    if (!node || !node.getBoundingClientRect) return
    
    let rect = node.getBoundingClientRect()
    let height = rect.height
    let index = +node.id.slice(1)
    let oldHeight = positions.value[index]?.height
    let dValue = oldHeight - height
    if (dValue) {
      positions.value[index].bottom = positions.value[index]?.bottom - dValue
      positions.value[index].height = height
      for (let k = index + 1; k < positions.value.length; k++) {
        positions.value[k].top = positions.value[k - 1]?.bottom
        positions.value[k].bottom = positions.value[k]?.bottom - dValue
      }
    }
  })
}

// 设置开始偏移
const setStartOffset = () => {
  let startOffset
  if (start.value >= 1) {
    let size =
      positions.value[start.value].top -
      (positions.value[start.value - aboveCount.value]
        ? positions.value[start.value - aboveCount.value].top
        : 0)
    startOffset = positions.value[start.value - 1].bottom - size
  } else {
    startOffset = 0
  }
  content.value.style.transform = `translate3d(0,${startOffset}px,0)`
}

// 滚动事件
const scrollEvent = () => {
  let scrollTop = list.value.scrollTop
  start.value = getStartIndex(scrollTop)
  end.value = start.value + visibleCount.value
  setStartOffset()
}

// 音频播放器实例
const audioPlayer = ref(null)

// TTS播放处理（精简版）
const handlePlayTTS = async (messageId) => {
  // 如果TTS功能关闭，直接返回
  if (!props.ttsEnabled) return
  
  const message = props.messages.find(msg => msg.id === messageId)
  if (!message) return

  try {
    // 停止当前播放
    handleStopTTS()

    // 获取音频结果，使用纯文本进行TTS
    const plainText = MarkdownService.getPlainText(message.content)
    const currentVoice = ttsService.getCurrentVoice()
    console.log('🎵 ChatList TTS调用:', { messageId, currentVoice, text: plainText.substring(0, 20) + '...' })
    const audioResult = await ttsService.generateAudio(plainText, messageId, currentVoice)
    
    // 处理不同的结果类型
    if (audioResult.startsWith('web-speech-api:')) {
      // Web Speech API已播放
      playingMessageId.value = messageId
    } else if (audioResult.startsWith('direct-playback:')) {
      // 使用Web Speech API播放
      await playWithWebSpeechAPI(plainText, messageId)
    } else {
      // 播放音频文件
      await playAudioFile(audioResult, messageId)
    }
    
  } catch (error) {
    console.error('TTS播放失败:', error)
    playingMessageId.value = null
    showNotification('语音播放失败', 'error')
  }
}

// 播放音频文件
const playAudioFile = async (audioUrl, messageId) => {
  try {
    audioPlayer.value = new Audio(audioUrl)
    
    audioPlayer.value.onended = () => {
      playingMessageId.value = null
      audioPlayer.value = null
    }
    
    audioPlayer.value.onerror = () => {
      playingMessageId.value = null
      audioPlayer.value = null
      console.error('音频播放失败')
    }
    
    audioPlayer.value.onpause = () => {
      // 如果是因为停止操作导致的暂停，不重置状态
      if (playingMessageId.value === messageId) {
        playingMessageId.value = null
      }
    }
    
    await audioPlayer.value.play()
    playingMessageId.value = messageId
  } catch (error) {
    console.error('音频播放启动失败:', error)
    playingMessageId.value = null
    audioPlayer.value = null
  }
}

// 使用Web Speech API播放
const playWithWebSpeechAPI = async (text, messageId) => {
  if (!('speechSynthesis' in window)) {
    throw new Error('Web Speech API not supported')
  }

  return new Promise((resolve, reject) => {
    const utterance = new SpeechSynthesisUtterance(text)
    utterance.lang = 'zh-CN'
    utterance.rate = 0.9
    utterance.pitch = 1.0
    utterance.volume = 1.0

    utterance.onstart = () => playingMessageId.value = messageId
    utterance.onend = () => {
      playingMessageId.value = null
      resolve()
    }
    utterance.onerror = (error) => {
      playingMessageId.value = null
      reject(new Error(`Web Speech API error: ${error.error}`))
    }

    window.speechSynthesis.speak(utterance)
  })
}

// 显示通知（统一方法）
const showNotification = (message, type = 'info') => {
  const notification = document.createElement('div')
  const colors = {
    info: '#007AFF',
    error: '#FF3B30',
    success: '#34C759'
  }
  
  notification.style.cssText = `
    position: fixed;
    top: 20px;
    right: 20px;
    background: ${colors[type]};
    color: white;
    padding: 12px 16px;
    border-radius: 8px;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
    z-index: 10000;
    max-width: 300px;
    font-size: 14px;
  `
  notification.textContent = message
  
  document.body.appendChild(notification)
  
  setTimeout(() => {
    if (notification.parentNode) {
      notification.parentNode.removeChild(notification)
    }
  }, 3000)
}

const handleStopTTS = () => {
  // 先重置播放状态
  playingMessageId.value = null
  
  // 停止音频文件播放
  if (audioPlayer.value) {
    audioPlayer.value.pause()
    audioPlayer.value.currentTime = 0
    audioPlayer.value = null
  }
  
  // 停止Web Speech API播放
  if ('speechSynthesis' in window) {
    window.speechSynthesis.cancel()
  }
  
  console.log('🛑 停止TTS播放')
}

const handleUpdateAudioUrl = (messageId, audioUrl) => {
  const message = props.messages.find(msg => msg.id === messageId)
  if (message) {
    message.audioUrl = audioUrl
  }
}

// 挂载
onMounted(() => {
  screenHeight.value = list.value.clientHeight
  start.value = 0
  end.value = start.value + visibleCount.value
  initPositions()
})

// 更新
onUpdated(() => {
  nextTick(() => {
    if (!items.value || !items.value.filter(node => node).length) {
      return
    }
    updateItemsSize()
    if (positions.value.length > 0) {
      let height = positions.value[positions.value.length - 1].bottom
      phantom.value.style.height = height + 'px'
      setStartOffset()
    }
  })
})

// 监听列表数据
watch(() => props.messages, initPositions)
</script>


<style scoped>
@import './index.css';
</style>
